#include "eigen/rnn.h"
#include "eigen/normal.h"
#include <Eigen/Dense>

namespace  ldl_eigen
{
RNN::RNN(int64_t input_size, int64_t hidden_size)
{
    m_input_size = input_size;
    m_output_size = input_size;
    m_hidden_size = hidden_size;

    m_weight_xh = Normal::matrix(input_size, hidden_size, 0, 0.01*0.01);
    m_weight_hh = Normal::matrix(hidden_size, hidden_size, 0, 0.01*0.01);
    m_bias_h.resize(hidden_size);
    for(auto &item:m_bias_h)
    {
        item = 0;
    }

    m_weight_ho = Normal::matrix(hidden_size, m_hidden_size, 0, 0.01*0.01);
    m_bias_h.resize(input_size);
    for(auto &item:m_bias_h)
    {
        item = 0;
    }
}

static void vector_like(const std::vector<std::vector<std::vector<float>>> &src, std::vector<std::vector<std::vector<float>>> &des)
{
    // 清空目标向量（如果它不为空）
    des.clear();

    // 遍历 src 的每一层
    for (const auto &outer_vec : src) {
        // 在 des 中添加一个新的二维向量
        des.emplace_back();

        // 遍历当前层的每个中间向量
        for (const auto &inner_vec : outer_vec) {
            // 在 des 的当前二维向量中添加一个大小相同但初始化为 0.0f 的一维向量
            des.back().emplace_back(inner_vec.size(), 0.0f);
        }
    }
}

void RNN::forward(const std::vector<std::vector<std::vector<float>>> &input)
{
    auto num_steps = input.size();
    auto batch_size = input.at(0).size();
    auto input_size = input.at(0).at(0).size();
    vector_like(input, m_output);

    for(int64_t step = 0; step < num_steps; step++)
    {
        for(int64_t batch = 0; batch < batch_size; batch++)
        {
            // input.at()
            Eigen::Map<const Eigen::VectorXf> single_input(input.at(step).at(batch).data(), input_size);
            Eigen::Map<Eigen::VectorXf> single_output(m_output.at(step).at(batch).data(), input_size);
            m_hidden_variable = (single_input * m_weight_xh).array() + (m_hidden_variable * m_weight_hh).array() + m_bias_h.array();
            single_output = (m_hidden_variable * m_weight_ho).array() + m_bias_o.array();
            // m_output.at(step).at(batch) = si
            // auto hidden = input.at(step).at(batch) * m_weight_xh;
        }
    }
}


void RNN::backward()
{
    // TODO
}
}